package tools;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;

/**
 * Fonctions pour manipuler des fichiers.
 * @author Guillaume Poças
 */
public class FileUtils {

	/**
	 * Constructeur vide.
	 */
	public FileUtils(){	}

	/**
	 * Créer un fichier.
	 * @param path
	 */
	public final static void createFile(String path){
		try{ 
			File fichier = new File(path); 
			fichier.createNewFile(); // Cette fonction doit être appelée au sein d'un bloc TRY 
		} 
		catch (IOException e){ 
			System.out.println("Impossible de créer le fichier"); 
		}
	}

	/**
	 * Lister les fichiers d'un repertoire.
	 * @param directoryPath
	 * @return la liste des fichiers
	 */
	public final static File[] listFiles(String directoryPath){ 
		File[] files = null; 
		File directoryToScan = new File(directoryPath); 
		files = directoryToScan.listFiles();

		//Debug
		//for(File file : files) System.out.println("Fichier "+file.getName());

		return files; 
	}

	/**
	 * Supprimer un fichier.
	 * @param directoryPath
	 * @param fileName
	 * @return le fichier supprimé
	 */
	public final static File[] cleanFile(String directoryPath, String fileName){ 
		File[] files = null; 
		File directoryToScan = new File(directoryPath); 
		files = directoryToScan.listFiles();

		if(files.length != 0)
			for(File file : files)
				if(file.getName().equalsIgnoreCase(fileName))	file.delete();

		//Debug
		//for(File file : files) System.out.println("Fichier "+file.getName());

		return files; 
	}

	/**
	 * Supprime les fichiers d'un dossier.
	 * @param directoryPath
	 * @return les fichiers supprimés
	 */
	public final static File[] cleanDirectory(String directoryPath){ 
		File[] files = null; 
		File directoryToScan = new File(directoryPath); 
		files = directoryToScan.listFiles();

		if(files.length != 0)
			for(File file : files)
				file.delete();

		//Debug
		//for(File file : files) System.out.println("Fichier "+file.getName());

		return files; 
	} 

	/**
	 * Copie d'un fichier
	 * @param currentFile
	 * @param newFile
	 * @param bufferSize
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public final static void copyFileBuffered(final String currentFile, final String newFile, final int bufferSize) throws FileNotFoundException, IOException {  
		final BufferedReader in = new BufferedReader(new FileReader(currentFile), bufferSize * 1024);  
		try {  
			final BufferedWriter out = new BufferedWriter(new FileWriter(newFile), bufferSize * 1024);  
			try {  
				int s = in.read();  
				while(s != -1) {  
					out.write(s);  
					s = in.read();  
				}
				out.flush();  
			} finally {  
				out.close();  
			}
		} finally {  
			in.close();  
		}
	}

	/**
	 * Copie et chiffrement d'un fichier.
	 * Protocole Diffie-Hellmann.
	 * @param currentFile
	 * @param newFile
	 * @param bufferSize
	 * @param dh_key
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public final static void copyFileBufferedEncryptedDH(final String currentFile, final String newFile, final int bufferSize, String dh_key) throws FileNotFoundException, IOException {  
		final BufferedReader in = new BufferedReader(new FileReader(currentFile), bufferSize * 1024);
		byte[] key = dh_key.getBytes();
		int i = 0;
		try {  
			final BufferedWriter out = new BufferedWriter(new FileWriter(newFile), bufferSize * 1024);  
			try {  
				int s = in.read();
				int s_c = (s ^ key[i%dh_key.length()]);
				while(s != -1) {
					i++;
					out.write(s_c);  
					s = in.read();
					s_c = (s ^ key[i%dh_key.length()]);
				}
				out.flush();  
			} finally {  
				out.close();  
			}
		} finally {  
			in.close();  
		}
	}

	/**
	 * Envoi d'un fichier en TCP.
	 * @param socket
	 * @param originFile
	 * @param newFile
	 */
	public final static void tcpSendFile(Socket socket, String originFile, String newFile){
		int n, cpt = 0, size = 1024;
		byte buf[] = new byte[size];
		InputStream in = null;
		OutputStream out = null;

		File file = new File(originFile);

		try {
			in = new FileInputStream(file);
			out = socket.getOutputStream();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		/* n = (int)(file.length()/size)+1;
        try {
			out.write(StringUtils.stringToBytes(String.valueOf(n)));
			out.flush();
			System.out.println("Nbre Iter = "+n+" &Length = "+file.length());
		} catch (IOException e1) {
			e1.printStackTrace();
		}*/

		System.out.println("Sending begin");
		try {
			while((n = in.read(buf,0,size))!=-1){
				//System.out.println("Cpt = "+cpt+" et "+n);
				out.write(buf,0,n);
				out.flush();
				cpt++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Sending end");

		try {
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public final static void tcpWaitingFileByWeight(Socket socket, String path, long weig){
		int n = 0, cpt = 1, size = 1024;
		long weigth = weig, currWeigth = 0;
		byte buf[] = new byte[size];
		InputStream in = null;
		OutputStream out = null;

		try {
			in = socket.getInputStream();
			out = new FileOutputStream(path);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		System.out.println("Waiting begin");
		try {
			while(currWeigth != weigth){
				n = in.read(buf,0,size);
				//System.out.println("Cpt = "+cpt+" et "+n);
				out.write(buf,0,n);
				out.flush();
				cpt++;
				currWeigth += n;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Waiting end");

		try {
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Réception d'un fichier en TCP.
	 * @param socket
	 * @param path
	 */
	public final static void tcpWaitingFile(Socket socket, String path){
		int n = 0, iter = 0, cpt = 1, size = 1024;
		byte buf[] = new byte[size];
		InputStream in = null;
		OutputStream out = null;

		try {
			in = socket.getInputStream();
			out = new FileOutputStream(path);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		try {
			n = in.read(buf);
			System.out.println("Nbre Iter = "+StringUtils.bytesToStringWithoutSpaces(buf));
			iter = Integer.parseInt(StringUtils.bytesToStringWithoutSpaces(buf));
		} catch (IOException e1) {
			e1.printStackTrace();
		}

		System.out.println("Waiting begin");
		try {
			while(n != -1){
				n = in.read(buf,0,size);
				System.out.println("Cpt = "+cpt+" et "+n);
				out.write(buf,0,n);
				out.flush();
				cpt++;
				if(n != size){
					iter++;
				}
				if(iter == cpt && n != size){
					//if(n != size){
					System.out.println("Dernière itération");
					//n = in.read(buf,0,size);
					System.out.println("Cpt = "+cpt+" et "+n);
					//out.write(buf,0,n);
					//out.flush();
					//if(n != size) System.out.println("Debug contenu paquet "+buf.toString());
					n = -1;
				}
				//cas d'une seule itération
				else if(cpt > iter && iter == 1)	n = -1;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Waiting end");

		try {
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Envoi de bytes en TCP.
	 * @param socket
	 * @param tab
	 * @throws IOException
	 */
	public final static void tcpSendBytes(Socket socket, byte[] tab) throws IOException {
		System.out.println("Sending begin");
		OutputStream out = socket.getOutputStream();
		out.write(ByteBuffer.allocate(4).putInt(tab.length).array());

		out.write(tab);
		out.flush();
		out.close();
		System.out.println("Sending end");
	}

	/**
	 * Réception de bytes en TCP.
	 * @param socket
	 * @throws IOException
	 */
	public final static void tcpWaitingBytes(Socket socket) throws IOException {
		System.out.println("Waiting begin");
		byte[] buf = new byte[4];
		InputStream in = socket.getInputStream();
		in.read(buf);
		int bufSize = ByteBuffer.wrap(buf).getInt();

		buf = new byte[bufSize];
		in.read(buf);
		in.close();
		System.out.println("Waiting end");
	}

	public static String readableFileSize(long size) {
		if(size <= 0) return "0";
		final String[] units = new String[] { "o", "Ko", "Mo", "Go", "To" };
		int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
		return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
	}

	public static byte[] fileToByteArray(File file, int length){
		byte[] fileContent = new byte[length];

		try {
			FileInputStream input = new FileInputStream(file);
			input.read(fileContent,0,length);
			input.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		return fileContent;
	}

	public static void byteArrayToFile(byte[] fileContent, String filePath){
		File file = new File(filePath);
		try {
			file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}

		try { 
			FileOutputStream output = new FileOutputStream(file);
			try {
				output.write(fileContent, 0, fileContent.length);
			} finally {  
				output.close();  
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}  catch (IOException e) {
			e.printStackTrace();
		}
	}

}
